<?php

namespace app\common\service;

use app\common\entity\ResponseData;
use app\common\util\plug\{
    PlugCreateController,
    PlugCreateLog,
    PlugCreateRoutes,
    PlugCreateTable,
    PlugInstall,
    PlugLoadConfig,
    PlugUnzip
};
use app\model\Plugs;
use think\db\exception\DbException;
use think\facade\Db;
use think\File;

class PlugService
{
    protected $installer;

    public function __construct()
    {
        $this->installer = new PlugInstall();
    }

    /**
     * @param \think\File|\think\file\UploadedFile $file
     */
    public function installByZip($file)
    {
        try {
            Db::startTrans();
            $file = $file->move(__PLUG_PATH__, $file->getOriginalName());
            $this->installer->setFile($file);
            $this->processInstallSteps();
            
            Db::commit();
            return $this->installer->handle();
        } catch (\Exception $e) {
            Db::rollback();
            throw $e;
        }
    }

    public function installByGit(int $id)
    {
        try {
            Db::startTrans();
            
            $plug = Plugs::findOrFail($id);
            $dir = $this->cloneRepository($plug);
            
            if (!$this->validateConfig($dir)) {
                throw new \Exception('Invalid plugin configuration');
            }
            
            $this->processInstallSteps();
            
            Db::commit();
            return ResponseData::success($this->installer->handle());
        } catch (\Exception $e) {
            Db::rollback();
            throw $e;
        }
    }

    protected function processInstallSteps(): void
    {
        new PlugUnzip($this->installer);
        new PlugLoadConfig($this->installer);
        new PlugCreateTable($this->installer);
        new PlugCreateLog($this->installer);
        new PlugCreateController($this->installer);
        new PlugCreateRoutes($this->installer);
    }

    protected function cloneRepository(Plugs $plug): string
    {
        $dir = escapeshellarg('..'.DIRECTORY_SEPARATOR.'plug'.DIRECTORY_SEPARATOR.$plug->name);
        $command = sprintf(
            'cd %s && git clone %s %s',
            escapeshellarg('..'.DIRECTORY_SEPARATOR.'plug'),
            escapeshellarg($plug->git_url),
            $dir
        );
        
        system($command, $code);
        
        if ($code !== 0) {
            throw new \Exception('Failed to clone repository');
        }
        
        return $dir;
    }

    protected function validateConfig(string $dir): bool
    {
        return file_exists($dir.DIRECTORY_SEPARATOR.'v-plug.yaml');
    }
}
